using System;

namespace Framework
{
    public class BehaviorTree<T> : IBehaviorTree
    {
        public event Action<T> Started;
        public event Action<T> Ended;
        
        private int _updatePeriod = 1;
        private int _updateCounter = 0;
        private TaskStatus _status = TaskStatus.Invalid;
        private T _context;
        private Behavior<T> _root;

        public BehaviorTree(T context, Behavior<T> root, int updatePeriod = 1)
        {
            _context = context;
            _root = root;
            _updatePeriod = updatePeriod;

            _root.Started += OnTaskStart;
            _root.Ended += OnTaskEnd;
        }
        
        public void Dispose()
        {
            _root.Started -= OnTaskStart;
            _root.Ended -= OnTaskEnd;
            if (_root.status == TaskStatus.Running)
            {
                _root.OnEnd(_context);
            }
            _root.Invalidate();
            if (_context is IDisposable)
            {
                (_context as IDisposable).Dispose();
            }
        }

        public TaskStatus Tick()
        {
            if (_status == TaskStatus.Invalid)
            {
                _status = TaskStatus.Running;
            }
            ++_updateCounter;
            if (_updateCounter >= _updatePeriod)
            {
                _status = _root.Tick(_context);
                _updateCounter -= _updatePeriod;
            }
            return _status;
        }

        private void OnTaskStart()
        {
            Started.SafeInvoke(_context);
        }

        private void OnTaskEnd()
        {
            Ended.SafeInvoke(_context);
        }
    }
}